﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Globalization;
using System.Windows.Data;

namespace Gmantis.Controls
{
    [TemplatePart(Name = "ScrollViewer", Type = typeof(ScrollViewer)), StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(ListViewerItem))]
    public class ListViewer : ItemsControl, INotifyPropertyChanged
    {
        // Fields
        private BitmapCache _cache = new BitmapCache();
        internal System.Windows.Controls.ScrollViewer _elementScrollViewer;
        private Point _finalPosition;
        private double _finalZoom = 1.0;
        private Point _initialPosition;
        private Point _initialScreenPosition;
        private double _initialZoom = 1.0;
        internal bool _isLoaded;
        private bool _isScrolling;
        private bool _isZooming;
        private DoubleAnimation _moveAnimation = new DoubleAnimation();
        private Action _moveCompleted;
        private Storyboard _moveStoryboard = new Storyboard();
        private ListViewerPanel _panel;
        private BitmapCache _resizeableCache;
        private double _startHorizontalOffset;
        private double _startManipulationX;
        private double _startManipulationY;
        private double _startVerticalOffset;
        private double _startZoom;
        private bool _updatePostionOnZoomChanged = true;
        public static readonly DependencyProperty ButtonBackgroundProperty = DependencyProperty.Register("ButtonBackground", typeof(Brush), typeof(ListViewer), null);
        public static readonly DependencyProperty ButtonForegroundProperty = DependencyProperty.Register("ButtonForeground", typeof(Brush), typeof(ListViewer), null);
        public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(ListViewer), null);
        internal static readonly DependencyProperty HorizontalOffsetProperty = DependencyProperty.Register("HorizontalOffset", typeof(double), typeof(ListViewer), new PropertyMetadata(0.0, (d, a) => (d as ListViewer).OnHorizontalOffsetChanged()));
        public static readonly DependencyProperty HorizontalScrollBarVisibilityProperty = DependencyProperty.Register("HorizontalScrollBarVisibility", typeof(ScrollBarVisibility), typeof(ListViewer), new PropertyMetadata(ScrollBarVisibility.Auto, new PropertyChangedCallback(ListViewer.OnHorizontalScrollBarVisibilityPropertyChanged)));
        public static readonly DependencyProperty IsSwipeEnabledProperty = DependencyProperty.Register("IsSwipeEnabled", typeof(bool), typeof(ListViewer), new PropertyMetadata(true));
        public static readonly DependencyProperty ItemHeightProperty = DependencyProperty.Register("ItemHeight", typeof(double), typeof(ListViewer), new PropertyMetadata((double)1.0 / (double)0.0, new PropertyChangedCallback(ListViewer.OnItemHeightPropertyChanged)));
        public static readonly DependencyProperty ItemWidthProperty = DependencyProperty.Register("ItemWidth", typeof(double), typeof(ListViewer), new PropertyMetadata((double)1.0 / (double)0.0, new PropertyChangedCallback(ListViewer.OnItemWidthPropertyChanged)));
        public static readonly DependencyProperty MaxZoomProperty = DependencyProperty.Register("MaxZoom", typeof(double), typeof(ListViewer), new PropertyMetadata(3.0, new PropertyChangedCallback(ListViewer.OnMaxZoomPropertyChanged)));
        public static readonly DependencyProperty MinZoomProperty = DependencyProperty.Register("MinZoom", typeof(double), typeof(ListViewer), new PropertyMetadata(0.3, new PropertyChangedCallback(ListViewer.OnMinZoomPropertyChanged)));
        public static readonly DependencyProperty MouseOverBrushProperty = DependencyProperty.Register("MouseOverBrush", typeof(Brush), typeof(ListViewer), null);
        internal static readonly DependencyProperty MoveAnimationProperty = DependencyProperty.Register("MoveAnimation", typeof(double), typeof(ListViewer), new PropertyMetadata(1.0, (d, a) => (d as ListViewer).MoveAnimationStep((double)a.NewValue)));
        public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register("Orientation", typeof(Orientation), typeof(ListViewer), new PropertyMetadata(Orientation.Vertical, new PropertyChangedCallback(ListViewer.OnOrientationPropertyChanged)));
        public static readonly DependencyProperty PressedBrushProperty = DependencyProperty.Register("PressedBrush", typeof(Brush), typeof(ListViewer), null);
        public static readonly DependencyProperty PreviewItemTemplateProperty = DependencyProperty.Register("PreviewItemTemplate", typeof(DataTemplate), typeof(ListViewer), null);
        public static readonly DependencyProperty RefreshWhileScrollingProperty = DependencyProperty.Register("RefreshWhileScrolling", typeof(bool), typeof(ListViewer), new PropertyMetadata(true));
        internal const string ScrollViewerElementName = "ScrollViewer";
        internal static readonly DependencyProperty VerticalOffsetProperty = DependencyProperty.Register("VerticalOffset", typeof(double), typeof(ListViewer), new PropertyMetadata(0.0, (d, a) => (d as ListViewer).OnVerticalOffsetChanged()));
        public static readonly DependencyProperty VerticalScrollBarVisibilityProperty = DependencyProperty.Register("VerticalScrollBarVisibility", typeof(ScrollBarVisibility), typeof(ListViewer), new PropertyMetadata(ScrollBarVisibility.Auto, new PropertyChangedCallback(ListViewer.OnVerticalScrollBarVisibilityPropertyChanged)));
        public static readonly DependencyProperty ViewportGapProperty = DependencyProperty.Register("ViewportGap", typeof(double), typeof(ListViewer), new PropertyMetadata(0.5));
        public static readonly DependencyProperty ViewportPreviewGapProperty = DependencyProperty.Register("ViewportPreviewGap", typeof(double), typeof(ListViewer), new PropertyMetadata(5.0));
        public static readonly DependencyProperty ZoomModeProperty = DependencyProperty.Register("ZoomMode", typeof(ZoomMode), typeof(ListViewer), new PropertyMetadata(ZoomMode.Enabled, new PropertyChangedCallback(ListViewer.OnZoomModePropertyChanged)));
        public static readonly DependencyProperty ZoomProperty = DependencyProperty.Register("Zoom", typeof(ZoomUnit), typeof(ListViewer), new PropertyMetadata(new ZoomUnit(1.0), new PropertyChangedCallback(ListViewer.OnZoomPropertyChanged)));

        // Events
        public event EventHandler HorizontalOffsetChanged;

        public event EventHandler<EventArgs> ItemClick;

        public event EventHandler ItemContainerLoaded;

        public event EventHandler ItemContainerUnloading;

        public event EventHandler<GestureEventArgs> ItemHold;

        public event EventHandler<GestureEventArgs> ItemTap;

        public event PropertyChangedEventHandler PropertyChanged;

        public event EventHandler VerticalOffsetChanged;

        public event EventHandler ZoomChanged;

        // Methods
        public ListViewer()
        {
            base.DefaultStyleKey = typeof(ListViewer);
            this.SetCustomDefaultValues();
        }

        private void BeginMoveStoryboard(Point? anchoredScreenPosition = new Point?(), Point? finalPosition = new Point?(), double? finalZoom = new double?(), Action completed = null)
        {
            if (this._moveStoryboard.GetCurrentState() != ClockState.Active)
            {
                Point? nullable = anchoredScreenPosition;
                this._initialScreenPosition = nullable.HasValue ? nullable.GetValueOrDefault() : new Point();
                this._initialPosition = this.GetAbsolutePoint(this._initialScreenPosition);
                this._initialZoom = Math.Max(this.ActualMinZoom, Math.Min(this.ActualMaxZoom, this.ActualZoom));
            }
            else
            {
                this._moveStoryboard.Stop();
                this._initialPosition = this.GetAbsolutePoint(this._initialScreenPosition);
                this._initialZoom = Math.Max(this.ActualMinZoom, Math.Min(this.ActualMaxZoom, this.ActualZoom));
            }
            this.IsZooming = true;
            this._moveCompleted = completed;
            Point? nullable2 = finalPosition;
            this._finalPosition = nullable2.HasValue ? nullable2.GetValueOrDefault() : this._initialPosition;
            double? nullable3 = finalZoom;
            this._finalZoom = Math.Max(this.ActualMinZoom, Math.Min(this.ActualMaxZoom, nullable3.HasValue ? nullable3.GetValueOrDefault() : this.ActualZoom));
            this._moveStoryboard.Begin();
        }

        public void BringIndexIntoView(int index, Rect subOffset = new Rect(), bool changeZoomIfNecessary = true, Action completed = null)
        {
            Rect itemPosition = this.Panel.GetItemPosition(index);
            if (!subOffset.IsEmpty)
            {
                subOffset = this.Panel.ConvertToRenderCoordinates(subOffset);
                itemPosition = new Rect(itemPosition.X + subOffset.X, itemPosition.Y + subOffset.Y, subOffset.Width, subOffset.Height);
            }
            this.BringIntoView(itemPosition, changeZoomIfNecessary, completed);
        }

        public void BringIntoView(Rect area, bool changeZoomIfNecessary = true, Action completed = null)
        {
            if (this.ScrollViewer != null)
            {
                Point point;
                double actualZoom = this.ActualZoom;
                double num2 = actualZoom;
                if (changeZoomIfNecessary)
                {
                    num2 = Math.Max(this.ActualMinZoom, Math.Min(this.ActualMaxZoom, Math.Min(actualZoom, this.Panel.FillZoom)));
                }
                if (this.Orientation == Orientation.Vertical)
                {
                    double num3 = Math.Max((double)0.0, (double)((this.ScrollViewer.ActualHeight - area.Height) / 2.0));
                    double x = this.Panel.ConvertToAbsoluteCoordinates(this.ScrollViewer.HorizontalOffset);
                    double y = this.Panel.ConvertToAbsoluteCoordinates((double)(area.Top - num3));
                    point = new Point(x, y);
                }
                else
                {
                    double num6 = Math.Max((double)0.0, (double)((this.ScrollViewer.ActualWidth - area.Width) / 2.0));
                    double num7 = this.Panel.ConvertToAbsoluteCoordinates((double)(area.Left - num6));
                    double num8 = this.Panel.ConvertToAbsoluteCoordinates(this.ScrollViewer.VerticalOffset);
                    point = new Point(num7, num8);
                }
                this.BeginMoveStoryboard(null, new Point?(point), new double?(num2), completed);
            }
        }

        private double CalculateMaxScaleForBitmapCache()
        {
            int num = 0x800;
            Size maximumItemSize = this.Panel.GetMaximumItemSize();
            double num2 = Math.Min((double)(((double)num) / maximumItemSize.Width), (double)(((double)num) / maximumItemSize.Height));
            return Math.Min(this.ActualZoom, num2);
        }

        protected override void ClearContainerForItemOverride(DependencyObject element, object item)
        {
            ListViewerItem sender = element as ListViewerItem;
            if (this.ItemContainerUnloading != null)
            {
                this.ItemContainerUnloading(sender, new EventArgs());
            }
            if (element != item)
            {
                sender.PreviewContent = null;
                sender.PreviewContentTemplate = null;
                sender.ContentTemplate = null;
                sender.Content = null;
                sender.State = ListBoxItemState.Preview;
            }
        }

        private Point GetAbsolutePoint(Point screenPoint)
        {
            return this.Panel.ConvertToAbsoluteCoordinates(new Point(this.ScrollViewer.HorizontalOffset + screenPoint.X, this.ScrollViewer.VerticalOffset + screenPoint.Y));
        }

        protected override DependencyObject GetContainerForItemOverride()
        {
            ListViewerItem item = new ListViewerItem();
            item.SetBinding(FrameworkElement.StyleProperty, new Binding().From<ListViewer>(this, x => x.ItemStyle));
            return item;
        }

        public int GetIndexAt(Point screenPoint)
        {
            if (this.Panel != null)
            {
                return this.Panel.GetIndexAt(this.GetAbsolutePoint(screenPoint));
            }
            return -1;
        }

        private T GetTemplateChild<T>(string childName, bool required, ref string errors) where T : class
        {
            DependencyObject templateChild = base.GetTemplateChild(childName);
            ApplyTemplateHelper.VerifyTemplateChild(typeof(T), "template part", childName, templateChild, required, ref errors);
            return (templateChild as T);
        }

        private static Storyboard GetTemplateChildResource(FrameworkElement root, string resourceName, bool required, ref string errors)
        {
            return GetTemplateChildResource<Storyboard>(root, resourceName, required, ref errors);
        }

        private static T GetTemplateChildResource<T>(FrameworkElement root, string resourceName, bool required, ref string errors) where T : class
        {
            object child = root.Resources[resourceName];
            ApplyTemplateHelper.VerifyTemplateChild(typeof(T), "resource", resourceName, child, required, ref errors);
            return (child as T);
        }

        protected virtual void InitializePanel()
        {
            this.UpdateViewport();
            this.Panel.MouseLeftButtonDown += new MouseButtonEventHandler(this.OnMouseLeftButtonDown);
            this.Panel.Zoom = this.Zoom;
            this.Panel.SetBinding<ListViewer>(System.Windows.Controls.Panel.BackgroundProperty, this, x => x.Background);
            ScrollHelper helper = new ScrollHelper(this.Panel, true, true, true);
            helper.ScrollDelta += new EventHandler<ScrollDeltaEventArgs>(this.OnScrollDelta);
            if (!PlatformIndependent.IsInDesignMode(this))
            {
                ZoomHelper helper2 = new ZoomHelper(this.Panel, true, true, true);
                helper2.ZoomStarted += new EventHandler<ZoomStartedEventArgs>(this.OnZoomStarted);
                helper2.ZoomDelta += new EventHandler<ZoomDeltaEventArgs>(this.OnZoomDelta);
                helper2.ZoomCompleted += new EventHandler<ZoomCompletedEventArgs>(this.OnZoomCompleted);
                this.UpdatePanelOrientation();
            }
        }

        protected virtual void InitializeScrollViewerPart()
        {
            Binding binding = new Binding
            {
                Path = new PropertyPath("HorizontalOffset", new object[0]),
                Source = this._elementScrollViewer
            };
            base.SetBinding(HorizontalOffsetProperty, binding);
            Binding binding2 = new Binding
            {
                Path = new PropertyPath("VerticalOffset", new object[0]),
                Source = this._elementScrollViewer
            };
            base.SetBinding(VerticalOffsetProperty, binding2);
            this._elementScrollViewer.SizeChanged += new SizeChangedEventHandler(this.OnScrollViewerSizeChanged);
            this.UpdateScrollViewer();
        }

        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return (item is ListViewerItem);
        }

        private void MoveAnimationStep(double coef)
        {
            double zoom = this._initialZoom;
            double d = this._finalZoom / this._initialZoom;
            if (d != 1.0)
            {
                zoom = this._initialZoom * Math.Exp(Math.Log(d) * coef);
                this.SetZoom(new ZoomUnit(zoom));
                base.UpdateLayout();
            }
            double length = this._initialPosition.X + ((this._finalPosition.X - this._initialPosition.X) * coef);
            double num6 = this._initialPosition.Y + ((this._finalPosition.Y - this._initialPosition.Y) * coef);
            Size size = this.Panel.ConvertToRenderCoordinates(this.Panel.ConvertFromLayoutCoordinates(this.Panel.RenderSize));
            double offset = Math.Max(0.0, Math.Min(size.Width, this.Panel.ConvertToRenderCoordinates(length) - this._initialScreenPosition.X));
            double num3 = Math.Max(0.0, Math.Min(size.Height, this.Panel.ConvertToRenderCoordinates(num6) - this._initialScreenPosition.Y));
            this.ScrollViewer.ScrollToHorizontalOffset(offset);
            this.ScrollViewer.ScrollToVerticalOffset(num3);
        }

        public override void OnApplyTemplate()
        {
            string errors = string.Empty;
            base.OnApplyTemplate();
            this._isLoaded = true;
            this._elementScrollViewer = this.GetTemplateChild<System.Windows.Controls.ScrollViewer>("ScrollViewer", true, ref errors);
            if (this._elementScrollViewer != null)
            {
                this.InitializeScrollViewerPart();
            }
            if (!string.IsNullOrEmpty(errors))
            {
                this._isLoaded = false;
                if ((base.Template != null) && !PlatformIndependent.IsInDesignMode(this))
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Template cannot be applied to ListViewer.\nDetails: {0}", new object[] { errors }));
                }
            }
        }

        protected override void OnDoubleTap(GestureEventArgs e)
        {
            if (this.ZoomMode == ZoomMode.Enabled)
            {
                double num3;
                double actualZoom = this.ActualZoom;
                Point position = e.GetPosition(this);
                Point point2 = e.GetPosition(this.Panel);
                point2 = new Point(point2.X / actualZoom, point2.Y / actualZoom);
                double fillZoom = this.Panel.FillZoom;
                if (Math.Round(actualZoom, 3) != Math.Round(fillZoom, 3))
                {
                    num3 = fillZoom;
                }
                else
                {
                    num3 = actualZoom / 0.5;
                }
                this.BeginMoveStoryboard(new Point?(position), null, new double?(num3), null);
            }
        }

        protected override void OnHold(GestureEventArgs e)
        {
            if (this.Panel != null)
            {
                ListBoxItem sender = VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(null), (UIElement)null).FirstOrDefault<UIElement>(uie => (uie is ListBoxItem)) as ListBoxItem;
                if (sender != null)
                {
                    this.OnItemHold(sender, e);
                }
            }
        }

        private void OnHorizontalOffsetChanged()
        {
            if (this.Orientation == Orientation.Horizontal)
            {
                this.UpdateViewport();
            }
            this.RaiseHorizontalOffsetChanged();
        }

        private void OnHorizontalScrollBarVisibilityChanged(ScrollBarVisibility oldValue)
        {
            this.UpdateScrollViewer();
        }

        private static void OnHorizontalScrollBarVisibilityPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ListViewer viewer = d as ListViewer;
            ScrollBarVisibility oldValue = (ScrollBarVisibility)e.OldValue;
            viewer.OnHorizontalScrollBarVisibilityChanged(oldValue);
        }

        private void OnItemClick(ListViewerItem listBoxItem, System.Windows.RoutedEventArgs e)
        {
            if (this.ItemClick != null)
            {
                this.ItemClick(listBoxItem, new EventArgs());
            }
        }

        private void OnItemHeightChanged(double oldValue)
        {
            this.UpdateViewport();
        }

        private static void OnItemHeightPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ListViewer viewer = d as ListViewer;
            double oldValue = (double)e.OldValue;
            viewer.OnItemHeightChanged(oldValue);
        }

        protected virtual void OnItemHold(object sender, GestureEventArgs e)
        {
            if (this.ItemHold != null)
            {
                this.ItemHold(sender, e);
            }
        }

        protected virtual void OnItemTap(object sender, GestureEventArgs e)
        {
            if (this.ItemTap != null)
            {
                this.ItemTap(sender, e);
            }
        }

        private void OnItemWidthChanged(double oldValue)
        {
            this.UpdateViewport();
        }

        private static void OnItemWidthPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ListViewer viewer = d as ListViewer;
            double oldValue = (double)e.OldValue;
            viewer.OnItemWidthChanged(oldValue);
        }

        private void OnMaxZoomChanged(double oldValue)
        {
            if (this.Panel != null)
            {
                this.Panel.Refresh();
            }
        }

        private static void OnMaxZoomPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ListViewer viewer = d as ListViewer;
            double oldValue = (double)e.OldValue;
            viewer.OnMaxZoomChanged(oldValue);
        }

        private void OnMinZoomChanged(double oldValue)
        {
            if (this.Panel != null)
            {
                this.Panel.Refresh();
            }
        }

        private static void OnMinZoomPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ListViewer viewer = d as ListViewer;
            double oldValue = (double)e.OldValue;
            viewer.OnMinZoomChanged(oldValue);
        }

        private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (this.Panel != null)
            {
                Point position = e.GetPosition(null);
                ListViewerItem listBoxItem = this.HitTest(position).FirstOrDefault<UIElement>(uie => (uie is ListViewerItem)) as ListViewerItem;
                if (listBoxItem != null)
                {
                    this.OnItemClick(listBoxItem, e);
                }
            }
        }

        private void OnMoveAnimationCompleted(object sender, EventArgs e)
        {
            this.UpdateRenderAtScale();
            this.IsZooming = false;
            this.UpdateViewport();
            if (this._moveCompleted != null)
            {
                this._moveCompleted();
                this._moveCompleted = null;
            }
        }

        private void OnOrientationChanged(Orientation oldValue)
        {
            this.UpdatePanelOrientation();
            this.UpdateScrollViewer();
            if (this.Panel != null)
            {
                this.Panel.Refresh();
            }
        }

        private static void OnOrientationPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ListViewer viewer = d as ListViewer;
            Orientation oldValue = (Orientation)e.OldValue;
            viewer.OnOrientationChanged(oldValue);
        }

        private void OnScrollDelta(object sender, ScrollDeltaEventArgs e)
        {
            if (this.Orientation == Orientation.Vertical)
            {
                this.ScrollViewer.ScrollToVerticalOffset(this.ScrollViewer.VerticalOffset - e.DeltaScroll);
            }
            else
            {
                this.ScrollViewer.ScrollToHorizontalOffset(this.ScrollViewer.HorizontalOffset - e.DeltaScroll);
            }
        }

        private void OnScrollViewerSizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (this.Panel != null)
            {
                this.Panel.InvalidateOneItemZoom();
                this.Panel.InvalidateFillZoom();
            }
            this.UpdateViewport();
        }

        protected override void OnTap(GestureEventArgs e)
        {
            if (this.Panel != null)
            {
                ListBoxItem sender = VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(null), (UIElement)null).FirstOrDefault<UIElement>(uie => (uie is ListBoxItem)) as ListBoxItem;
                if (sender != null)
                {
                    this.OnItemTap(sender, e);
                }
            }
        }

        private void OnVerticalOffsetChanged()
        {
            if (this.Orientation == Orientation.Vertical)
            {
                this.UpdateViewport();
            }
            this.RaiseVerticalOffsetChanged();
        }

        private void OnVerticalScrollBarVisibilityChanged(ScrollBarVisibility oldValue)
        {
            this.UpdateScrollViewer();
        }

        private static void OnVerticalScrollBarVisibilityPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ListViewer viewer = d as ListViewer;
            ScrollBarVisibility oldValue = (ScrollBarVisibility)e.OldValue;
            viewer.OnVerticalScrollBarVisibilityChanged(oldValue);
        }

        private void OnZoomChanged(ZoomUnit oldValue)
        {
            if ((this.ScrollViewer != null) && (this.Panel != null))
            {
                if (this._updatePostionOnZoomChanged)
                {
                    double horizontalOffset = this.ScrollViewer.HorizontalOffset;
                    double verticalOffset = this.ScrollViewer.VerticalOffset;
                    double actualZoom = this.Panel.ActualZoom;
                    this.Panel.Zoom = this.Zoom;
                    this.Panel.UpdateLayout();
                    double num4 = this.Panel.ActualZoom;
                    this.ScrollViewer.ScrollToHorizontalOffset((horizontalOffset * num4) / actualZoom);
                    this.ScrollViewer.ScrollToVerticalOffset((verticalOffset * num4) / actualZoom);
                }
                else
                {
                    this.Panel.Zoom = this.Zoom;
                }
            }
            if (this.ZoomChanged != null)
            {
                this.ZoomChanged(this, new EventArgs());
            }
        }

        private void OnZoomCompleted(object sender, ZoomCompletedEventArgs e)
        {
            if (this.IsZooming)
            {
                this.UpdateRenderAtScale();
                this.IsZooming = false;
                this.UpdateViewport();
            }
        }

        private void OnZoomDelta(object sender, ZoomDeltaEventArgs e)
        {
            if (this.IsZooming)
            {
                this.SetZoom(new ZoomUnit(Math.Max(this.ActualMinZoom, Math.Min(this.ActualMaxZoom, this._startZoom * e.UniformCumulativeScale))));
                base.UpdateLayout();
                double offset = Math.Max(0.0, Math.Min(this.Panel.ActualHeight, ((this._startVerticalOffset * this.ActualZoom) - this._startManipulationY) + e.CumulativeTranslation.Y));
                double num2 = Math.Max(0.0, Math.Min(this.Panel.ActualWidth, ((this._startHorizontalOffset * this.ActualZoom) - this._startManipulationX) + e.CumulativeTranslation.X));
                this.ScrollViewer.ScrollToVerticalOffset(offset);
                this.ScrollViewer.ScrollToHorizontalOffset(num2);
            }
        }

        private void OnZoomModeChanged(ZoomMode oldValue)
        {
            this.UpdateScrollViewer();
        }

        private static void OnZoomModePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ListViewer viewer = d as ListViewer;
            ZoomMode oldValue = (ZoomMode)e.OldValue;
            viewer.OnZoomModeChanged(oldValue);
        }

        private static void OnZoomPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ListViewer viewer = d as ListViewer;
            ZoomUnit oldValue = (ZoomUnit)e.OldValue;
            viewer.OnZoomChanged(oldValue);
        }

        private void OnZoomStarted(object sender, ZoomStartedEventArgs e)
        {
            if (this.ZoomMode == ZoomMode.Enabled)
            {
                this.IsZooming = true;
                this._startZoom = this.ActualZoom;
                Point position = e.GetPosition(this.ScrollViewer);
                this._startManipulationX = position.X;
                this._startManipulationY = position.Y;
                this._startVerticalOffset = (this._startManipulationY + this.ScrollViewer.VerticalOffset) / this.ActualZoom;
                double extentWidth = this.ScrollViewer.ExtentWidth;
                double viewportWidth = this.ScrollViewer.ViewportWidth;
                double num3 = (extentWidth >= viewportWidth) ? this.ScrollViewer.HorizontalOffset : ((extentWidth - viewportWidth) / 2.0);
                this._startHorizontalOffset = (this._startManipulationX + num3) / this.ActualZoom;
            }
        }

        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            base.PrepareContainerForItemOverride(element, item);
            ListViewerItem sender = element as ListViewerItem;
            if (!object.ReferenceEquals(element, item))
            {
                DataTemplateSelector itemTemplateSelector = base.ItemTemplateSelector;
                DataTemplate template = (itemTemplateSelector != null) ? (itemTemplateSelector.SelectTemplate(item, element) ?? base.ItemTemplate) : base.ItemTemplate;
                if (!(item is FrameworkElement))
                {
                    sender.PreviewContent = item;
                }
                sender.PreviewContentTemplate = this.PreviewItemTemplate ?? template;
            }
            if (this.ItemContainerLoaded != null)
            {
                this.ItemContainerLoaded(sender, new EventArgs());
            }
        }

        private void RaiseHorizontalOffsetChanged()
        {
            if (this.HorizontalOffsetChanged != null)
            {
                this.HorizontalOffsetChanged(this, new EventArgs());
            }
        }

        protected void RaisePropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private void RaiseVerticalOffsetChanged()
        {
            if (this.VerticalOffsetChanged != null)
            {
                this.VerticalOffsetChanged(this, new EventArgs());
            }
        }

        public void ScrollToHorizontalOffset(double offset)
        {
            if (this._elementScrollViewer != null)
            {
                this._elementScrollViewer.ScrollToHorizontalOffset(offset);
            }
        }

        public void ScrollToVerticalOffset(double offset)
        {
            if (this.ScrollViewer != null)
            {
                this.ScrollViewer.ScrollToVerticalOffset(offset);
            }
        }

        private void SetCustomDefaultValues()
        {
            QuadraticEase ease = new QuadraticEase
            {
                EasingMode = EasingMode.EaseOut
            };
            this._moveAnimation.EasingFunction = ease;
            this._moveAnimation.Duration = TimeSpan.FromMilliseconds(500.0);
            this._moveAnimation.From = 0.0;
            this._moveAnimation.To = 1.0;
            Storyboard.SetTarget(this._moveAnimation, this);
            Storyboard.SetTargetProperty(this._moveAnimation, new PropertyPath("MoveAnimation", new object[0]));
            this._moveStoryboard.Completed += new EventHandler(this.OnMoveAnimationCompleted);
            this._moveStoryboard.Children.Add(this._moveAnimation);
        }

        private void SetZoom(ZoomUnit zoom)
        {
            this._updatePostionOnZoomChanged = false;
            this.Zoom = zoom;
            this._updatePostionOnZoomChanged = true;
        }

        private void UpdatePanelOrientation()
        {
            ListViewerPanel panel = this.Panel;
        }

        private void UpdateRenderAtScale()
        {
            double num = this.CalculateMaxScaleForBitmapCache();
            this.ResizableCache.RenderAtScale = num;
        }

        private void UpdateScrollViewer()
        {
            if (this.ScrollViewer != null)
            {
                this.ScrollViewer.HorizontalScrollBarVisibility = this.HorizontalScrollBarVisibility;
                this.ScrollViewer.VerticalScrollBarVisibility = this.VerticalScrollBarVisibility;
            }
        }

        internal void UpdateViewport()
        {
            if (this.Panel != null)
            {
                this.Panel.InvalidateMeasure();
            }
        }

        public void ZoomAnimation(double targetZoom, Point screenPoint, Action completed)
        {
            this.BeginMoveStoryboard(new Point?(screenPoint), null, new double?(targetZoom), completed);
        }

        // Properties
        public double ActualMaxZoom
        {
            get
            {
                if ((!double.IsNaN(this.MaxZoom) && !double.IsInfinity(this.MaxZoom)) && (this.MaxZoom >= 0.0))
                {
                    return this.MaxZoom;
                }
                return double.PositiveInfinity;
            }
        }

        public double ActualMinZoom
        {
            get
            {
                if ((!double.IsNaN(this.MinZoom) && !double.IsInfinity(this.MinZoom)) && (this.MinZoom >= 0.0))
                {
                    return this.MinZoom;
                }
                return 0.0;
            }
        }

        public double ActualZoom
        {
            get
            {
                if (this.Panel != null)
                {
                    return this.Panel.ActualZoom;
                }
                return 1.0;
            }
        }

        public Brush ButtonBackground
        {
            get
            {
                return (Brush)base.GetValue(ButtonBackgroundProperty);
            }
            set
            {
                base.SetValue(ButtonBackgroundProperty, value);
            }
        }

        public Brush ButtonForeground
        {
            get
            {
                return (Brush)base.GetValue(ButtonForegroundProperty);
            }
            set
            {
                base.SetValue(ButtonForegroundProperty, value);
            }
        }

        public CornerRadius CornerRadius
        {
            get
            {
                return (CornerRadius)base.GetValue(CornerRadiusProperty);
            }
            set
            {
                base.SetValue(CornerRadiusProperty, value);
            }
        }

        internal BitmapCache FixedCache
        {
            get
            {
                return this._cache;
            }
        }

        public ScrollBarVisibility HorizontalScrollBarVisibility
        {
            get
            {
                return (ScrollBarVisibility)base.GetValue(HorizontalScrollBarVisibilityProperty);
            }
            set
            {
                base.SetValue(HorizontalScrollBarVisibilityProperty, value);
            }
        }

        public bool IsScrolling
        {
            get
            {
                return this._isScrolling;
            }
        }

        public bool IsSwipeEnabled
        {
            get
            {
                return (bool)base.GetValue(IsSwipeEnabledProperty);
            }
            set
            {
                base.SetValue(IsSwipeEnabledProperty, value);
            }
        }

        public bool IsZooming
        {
            get
            {
                return this._isZooming;
            }
            private set
            {
                this._isZooming = value;
                this.RaisePropertyChanged("IsZooming");
            }
        }

        public double ItemHeight
        {
            get
            {
                return (double)base.GetValue(ItemHeightProperty);
            }
            set
            {
                base.SetValue(ItemHeightProperty, value);
            }
        }

        public double ItemWidth
        {
            get
            {
                return (double)base.GetValue(ItemWidthProperty);
            }
            set
            {
                base.SetValue(ItemWidthProperty, value);
            }
        }

        public double MaxZoom
        {
            get
            {
                return (double)base.GetValue(MaxZoomProperty);
            }
            set
            {
                base.SetValue(MaxZoomProperty, value);
            }
        }

        public double MinZoom
        {
            get
            {
                return (double)base.GetValue(MinZoomProperty);
            }
            set
            {
                base.SetValue(MinZoomProperty, value);
            }
        }

        public Brush MouseOverBrush
        {
            get
            {
                return (Brush)base.GetValue(MouseOverBrushProperty);
            }
            set
            {
                base.SetValue(MouseOverBrushProperty, value);
            }
        }

        public Orientation Orientation
        {
            get
            {
                return (Orientation)base.GetValue(OrientationProperty);
            }
            set
            {
                base.SetValue(OrientationProperty, value);
            }
        }

        protected internal ListViewerPanel Panel
        {
            get
            {
                if (this._panel == null)
                {
                    this._panel = this.GetItemsHost() as ListViewerPanel;
                    if (this._panel != null)
                    {
                        this.InitializePanel();
                    }
                }
                return this._panel;
            }
        }

        public Brush PressedBrush
        {
            get
            {
                return (Brush)base.GetValue(PressedBrushProperty);
            }
            set
            {
                base.SetValue(PressedBrushProperty, value);
            }
        }

        public DataTemplate PreviewItemTemplate
        {
            get
            {
                return (DataTemplate)base.GetValue(PreviewItemTemplateProperty);
            }
            set
            {
                base.SetValue(PreviewItemTemplateProperty, value);
            }
        }

        public bool RefreshWhileScrolling
        {
            get
            {
                return (bool)base.GetValue(RefreshWhileScrollingProperty);
            }
            set
            {
                base.SetValue(RefreshWhileScrollingProperty, value);
            }
        }

        internal BitmapCache ResizableCache
        {
            get
            {
                if (this._resizeableCache == null)
                {
                    this._resizeableCache = new BitmapCache();
                    this.UpdateRenderAtScale();
                }
                return this._resizeableCache;
            }
        }

        protected internal System.Windows.Controls.ScrollViewer ScrollViewer
        {
            get
            {
                return this._elementScrollViewer;
            }
        }

        public ScrollBarVisibility VerticalScrollBarVisibility
        {
            get
            {
                return (ScrollBarVisibility)base.GetValue(VerticalScrollBarVisibilityProperty);
            }
            set
            {
                base.SetValue(VerticalScrollBarVisibilityProperty, value);
            }
        }

        public double ViewportGap
        {
            get
            {
                return (double)base.GetValue(ViewportGapProperty);
            }
            set
            {
                base.SetValue(ViewportGapProperty, value);
            }
        }

        public double ViewportPreviewGap
        {
            get
            {
                return (double)base.GetValue(ViewportPreviewGapProperty);
            }
            set
            {
                base.SetValue(ViewportPreviewGapProperty, value);
            }
        }

        public ZoomUnit Zoom
        {
            get
            {
                return (ZoomUnit)base.GetValue(ZoomProperty);
            }
            set
            {
                base.SetValue(ZoomProperty, value);
            }
        }

        public ZoomMode ZoomMode
        {
            get
            {
                return (ZoomMode)base.GetValue(ZoomModeProperty);
            }
            set
            {
                base.SetValue(ZoomModeProperty, value);
            }
        }
    }

    public enum ZoomMode
    {
        Disabled,
        Enabled
    }
}
